﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using PloobsEngine;
using PloobsEngine.Cameras;
using PloobsEngine.Draw;
using PloobsEngine.Input;
using PloobsEngine.Light;
using PloobsEngine.Loader;
using PloobsEngine.Material;
using PloobsEngine.Modelo;
using PloobsEngine.Physics;
using PloobsEngine.Physics.Bepu;
using PloobsEngine.SceneControl;
using PloobsEngine.Utils;
using PloobsEngineDemo3;
using System;

namespace Etapa1.Screens
{    
    /// <summary>
    /// Shadow Scene using Cascade Shadow Mapping
    /// Good for large Outdoors Ambients 
    /// Uses filtering
    /// </summary>
    public class CSSScreen : SceneScreen
    {
        private BepuPhysicWorld physicWorld;
        private BrutalForceWorld mundo;
        private EngineStuff engine;
        CameraFirstPerson cam;
        DirectionalLight ld1;
        Vec3Interpolator inter = new Vec3Interpolator();

        public CSSScreen(EngineStuff es)
        {
            this.engine = es;
            physicWorld = new BepuPhysicWorld();
            mundo = new BrutalForceWorld(physicWorld);                                    
        }
        
        public override void LoadContent(EngineStuff es)
        {
            ///Used to throw balls
            ///IT IS NOT USED IN THIS SCREEN 
            ///THIS SHOW HOW CAN YOU USE THE XNA INPUT HELPER WITHOUT THE INPUT COMPONENT
            InputAdvanced inp = new InputAdvanced(engine);
            engine.AddComponent(inp);

            base.LoadContent(es);           

            #region Models

            ///Load Model From XML
            ExtractXmlModelLoader me = new ExtractXmlModelLoader();
            ModelLoaderData data = me.Load("shadow");

            ///Standard Procedure
            foreach (var item in data.ModelMeshesInfo)
            {
                ComposedPartsModel sm = new ComposedPartsModel(item);
                sm.LoadModelo();
                IPhysicObject pi = new TriangleMeshObject(sm, item.pos, Matrix.CreateFromQuaternion(item.ori) , item.scale);
                pi.isMotionLess = true;
                CustomDeferred shader = new CustomDeferred(item.HasTexture(TextureType.GLOW), item.HasTexture(TextureType.BUMP), item.HasTexture(TextureType.SPECULAR), item.HasTexture(TextureType.PARALAX));                
                shader.Initialize();
                IMaterial mat = new Material(shader);
                IObject obj4 = new SimpleObject(mat, pi, sm);
                mundo.AddObject(obj4);
            }

            #endregion            

            ///Setup the camera                        
            cam = new CameraFirstPerson(true);            
            ///Dont set the far plane too large, cause it destroys the shadown map precision
            cam.FarPlane = 2000;
            cam.NearPlane = 1;

            LightThrowBepu lt = new LightThrowBepu(mundo, engine);            

            ///Setup the Directional Cast Shadow Light
            #region NormalLight
            ld1 = new DirectionalLight(new Vector3(0.2f, -1, 0.2f), Color.White);
            ld1.CastShadown = true;
            float li = 0.9f;
            ld1.LightIntensity = li;            
            mundo.AddLight(ld1);
            
            #endregion

            ////Criacao de uma Tecnica
            DeferredRenderTechnic dr = new DeferredRenderTechnic(engine);
            
            ///Enable Shadow in the technic
            IRenderTechnic[] rt = new IRenderTechnic[] { dr };
            this.RenderTechnics = rt;
            ///Some Ambient Color
            dr.DeferredFinalCombination.AmbientColor = new Color(new Vector3(0.1f));            
            CSSShadowLightMap slm = new CSSShadowLightMap();
            slm.DirectionalShadowRender.ShadowMapSize = 512;
            slm.DirectionalShadowRender.SplitConstant = 0.7f;
            slm.DirectionalShadowRender.ShadowFilteringType = DirectionalShadowFilteringType.PCF7x7;
            dr.DeferredLightMap = slm;
            //dr.isDebug = true;
            //dr.IsDebugImageEnabled = true;
            mundo.AddCamera(cam);
            this.World = mundo;

            ///Soft Antialiasing enabled
            dr.AddPostEffect(new AntiAliasingPostEffect());

            ///Interpolator to change lightDirection
            inter.Start(new Vector3(0, -1, 0), new Vector3(1, -1, 1), 3, true);
        }

        /// <summary>
        /// Override the screen update method
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="otherScreenHasFocus"></param>
        /// <param name="coveredByOtherScreen"></param>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
        {
            ///Interpolator Update
            inter.Update(EngineStuff.GetCurrentGameTime());
            ld1.LightDirection = inter.CurrentValue;

            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);

            ///Restart Interpolation
            ///THIS TIME, THE INPUT ADVANCED WAS NOT USED
            if (Keyboard.GetState().IsKeyDown(Keys.J))
            {
                inter.Start(new Vector3(0, -1, 0), new Vector3(1, -1, 1), 3, true);
            }
        }

        
    }
}


